package com.idanchuang.component.businesslog.es.annotations;

import com.idanchuang.component.businesslog.es.index.*;
import org.elasticsearch.ElasticsearchStatusException;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.core.AcknowledgedResponse;
import org.elasticsearch.client.indexlifecycle.GetLifecyclePolicyRequest;
import org.elasticsearch.client.indices.IndexTemplatesExistRequest;
import org.elasticsearch.client.indices.PutIndexTemplateRequest;
import org.elasticsearch.common.unit.TimeValue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.*;

/**
 * The OpenDistroIndexLifeCycle
 *
 * @since 2020/7/16
 */
public class OpenDistroIndexLifeCycle implements IndexLifeCycle {

    private static final Logger log = LoggerFactory.getLogger(OpenDistroIndexLifeCycle.class);

    private CustomRestHighLevelClient client;

    public OpenDistroIndexLifeCycle(RestHighLevelClient restHighLevelClient) {
        this.client = (CustomRestHighLevelClient) restHighLevelClient;
    }

    @Override
    public String findIlmPolicy(Document document) throws IOException {
        String rollMode = document.rollMode().toString();
        String maxAge = document.maxDays() <= 0 ? "0d" : document.maxDays() + "d";

        // 不执行策略
        if (document.rollMode() == RollMode.NONE && document.maxDays() <= 0) {
            return null;
        }
        // 执行策略
        String policyName = ("policy_ro_" + rollMode + "_del_" + maxAge).toLowerCase();
        GetLifecyclePolicyRequest request = new GetLifecyclePolicyRequest(policyName);
        try {
            client.indexManage().getLifecyclePolicy(request, RequestOptions.DEFAULT);
        } catch (ElasticsearchStatusException e) {
            if (e.getMessage().contains("resource_not_found_exception")) {
                List<StatusPolicy> states = new ArrayList<>();
                TimeValue timeValue;
                switch (document.rollMode()) {
                    case MINUTE:
                        timeValue = TimeValue.parseTimeValue("1m", "1m");
                        break;
                    case HOUR:
                        timeValue = TimeValue.parseTimeValue("1h", "1h");
                        break;
                    case DAY:
                        timeValue = TimeValue.parseTimeValue("1d", "1d");
                        break;
                    case WEEK:
                        timeValue = TimeValue.parseTimeValue("7d", "7d");
                        break;
                    case MONTH:
                        timeValue = TimeValue.parseTimeValue("30d", "30d");
                        break;
                    case YEAR:
                        timeValue = TimeValue.parseTimeValue("365d", "365d");
                        break;
                    default:
                        timeValue = null;
                        break;
                }
                String defaultState = null;
                String description = "ingesting logs";
                if (document.maxDays() > 0) {
                    defaultState = "search";
                    List<TransitionsPolicy> transitions = new ArrayList<>();
                    ActionRole conditions = new ActionRole(null, TimeValue.parseTimeValue(maxAge, maxAge), null);
                    transitions.add(new TransitionsPolicy("delete", conditions));
                    states.add(new StatusPolicy(defaultState, null, transitions));

                    List<ActionsPolicy> actions = new ArrayList<>();
                    actions.add(new ActionsPolicy("delete", null));
                    states.add(new StatusPolicy("delete", actions, null));
                }

                if (timeValue != null) {
                    defaultState = "ingest";
                    List<ActionsPolicy> actions = new ArrayList<>();
                    List<TransitionsPolicy> transitions = new ArrayList<>();
                    ActionRole action = new ActionRole(null, timeValue, null);
                    actions.add(new ActionsPolicy("rollover", action));
                    transitions.add(new TransitionsPolicy("search", null));
                    states.add(new StatusPolicy(defaultState, actions, transitions));
                }

                IndexManagerPolicy policy = new IndexManagerPolicy(policyName, description, defaultState, states);
                PutIndexManagerPolicyRequest putRequest = new PutIndexManagerPolicyRequest(policy);
                AcknowledgedResponse response = client.indexManage().putLifecyclePolicy(putRequest, RequestOptions.DEFAULT);
                boolean acknowledged = response.isAcknowledged();
                if (acknowledged) {
                    log.info("create lifecyclePolicy {}", policyName);
                }
            }
        }
        return policyName;
    }

    @Override
    public void checkTemplate(String indexName, String policyName) throws IOException {
        String templateName = indexName + "_template";
        IndexTemplatesExistRequest request = new IndexTemplatesExistRequest(templateName);
        boolean exists = client.indices().existsTemplate(request, RequestOptions.DEFAULT);
        if (!exists) {
            PutIndexTemplateRequest putRequest = new PutIndexTemplateRequest(templateName);
            Map<String, Object> settings = new HashMap<>();
            settings.put("number_of_shards", 1);
            settings.put("number_of_replicas", 1);
            settings.put("opendistro.index_state_management.policy_id", policyName);
            settings.put("opendistro.index_state_management.rollover_alias", indexName);
            putRequest.settings(settings);
            putRequest.patterns(Collections.singletonList(indexName + "-*"));
            org.elasticsearch.action.support.master.AcknowledgedResponse response = client.indices()
                    .putTemplate(putRequest, RequestOptions.DEFAULT);
            boolean acknowledged = response.isAcknowledged();
            if (acknowledged) {
                log.info("create index template {}", templateName);
            }
        }
    }
}
